// websocketserverimpl.cpp
#include "websocketserverimpl.h"
#include "../core/logging.h"
namespace hhfox{
    WebSocketServerImpl::WebSocketServerImpl(const char *host, int port)
        : host_(host), port_(port) {
        }

    WebSocketServerImpl::~WebSocketServerImpl()
    {
    }

    void WebSocketServerImpl::setLoggerCallback(Logger && logger){
        custom::Logging::getInstance().setLoggerCallback(std::move(logger));
    }


    void WebSocketServerImpl::registerHandler(const std::string &uri, std::shared_ptr<IWebSocketHandler> handler)
    {
        handlers_[uri] = handler;
    }

    void WebSocketServerImpl::on_open(server *s, websocketpp::connection_hdl hdl)
    {
        server::connection_ptr con = s->get_con_from_hdl(hdl);
        auto uri = con->get_uri()->get_resource();
        CLOG(DEBUG) << "on_open from uri " << uri;
        std::string query = con->get_uri()->get_query();
        std::map<std::string, std::string> params;
        std::istringstream iss(query);
        std::string pair;
        while (std::getline(iss, pair, '&'))
        {
            size_t eq = pair.find('=');
            if (eq != std::string::npos)
            {
                std::string key = pair.substr(0, eq);
                std::string value = pair.substr(eq + 1);
                params[key] = value;
            }
        }

        auto handler = handlers_.find(uri);
        if (handler != handlers_.end())
        {
            handler->second->onOpen(hdl);
        }
        else
        {
            CLOG(WARNING) << "No handler registered for URI: " << uri;
        }
    }

    void WebSocketServerImpl::on_close(server *s, websocketpp::connection_hdl hdl)
    {
        server::connection_ptr con = s->get_con_from_hdl(hdl);
        auto uri = con->get_uri()->get_resource();
        CLOG(DEBUG) << "on_close from uri " << uri;
        auto handler = handlers_.find(uri);
        if (handler != handlers_.end())
        {
            handler->second->onClose(hdl);
        }
    }

    void WebSocketServerImpl::on_http(server *s, websocketpp::connection_hdl hdl)
    {
        server::connection_ptr con = s->get_con_from_hdl(hdl);
        auto uri = con->get_uri()->get_resource();
        CLOG(DEBUG) << "on_http from uri " << uri;
        con->append_header("Access-Control-Allow-Origin", "*");
        con->append_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
        con->append_header("Access-Control-Allow-Headers", "Content-Type");
        con->set_status(websocketpp::http::status_code::ok);
        con->set_body("OK");
        auto handler = handlers_.find(uri);
        if (handler != handlers_.end())
        {
            handler->second->onHttp(hdl);
        }
    }

    void WebSocketServerImpl::on_message(server *s, websocketpp::connection_hdl hdl, message_ptr msg)
    {
        server::connection_ptr con = s->get_con_from_hdl(hdl);
        auto uri = con->get_uri()->get_resource();
        std::string payload = msg->get_payload();
        CLOG(DEBUG) << "Received message from uri "<< uri <<" client: "<< payload;
        auto handler = handlers_.find(uri);
        if (handler != handlers_.end())
        {
            handler->second->onMessage(hdl);
        }
    }

    void WebSocketServerImpl::run()
    {
        try
        {
            svr_.init_asio();
            svr_.set_open_handler(std::bind(&WebSocketServerImpl::on_open, this,
                                            &svr_, std::placeholders::_1));
            svr_.set_close_handler(std::bind(&WebSocketServerImpl::on_close, this,
                                             &svr_, std::placeholders::_1));
            svr_.set_http_handler(std::bind(&WebSocketServerImpl::on_http, this,
                                            &svr_, std::placeholders::_1));
            svr_.set_message_handler(
                std::bind(&WebSocketServerImpl::on_message, this, &svr_,
                          std::placeholders::_1, std::placeholders::_2));
            svr_.clear_access_channels(websocketpp::log::alevel::frame_header |
                                       websocketpp::log::alevel::frame_payload |
                                       websocketpp::log::alevel::access_core);
            svr_.clear_access_channels(websocketpp::log::alevel::all);

            svr_.set_reuse_addr(true);
            CLOG(INFO) << "WebSocketService 监听: " << host_ << ":" << port_;
            websocketpp::lib::asio::ip::tcp::endpoint ep(
                boost::asio::ip::address::from_string(host_), port_);
            svr_.listen(ep);
            svr_.start_accept();
            svr_.run();
        }
        catch (websocketpp::exception const &e)
        {
            CLOG(ERROR) << "websocketpp::exception: (" << e.what() << ")";
        }
    }

    void WebSocketServerImpl::quit()
    {
        svr_.stop();
    }

    void WebSocketServerImpl::sendRawMessage(websocketpp::connection_hdl hdl, void *buff, size_t len, websocketpp::frame::opcode::value op)
    {
        svr_.send(hdl, (char *)buff, len, op);
    }

    void WebSocketServerImpl::sendRawMessage(websocketpp::connection_hdl hdl, const std::string &msg)
    {
        svr_.send(hdl, msg.data(), msg.size(), websocketpp::frame::opcode::text);
    }

    connection_ptr WebSocketServerImpl::get_con_from_hdl(connection_hdl hdl){
        return svr_.get_con_from_hdl(hdl);
    }


}